package cn.com.pc.content.controller;

import cn.com.pc.aaa.Constants;
import cn.com.pc.aaa.model.Identity;
import cn.com.pc.content.annotation.LogRequired;
import cn.com.pc.content.domain.Biz;
import cn.com.pc.content.domain.Site;
import cn.com.pc.content.domain.audit.AuditStatus;
import cn.com.pc.content.domain.content.ContentType;
import cn.com.pc.content.domain.post.Post;
import cn.com.pc.content.domain.post.PostNotFoundException;
import cn.com.pc.content.dto.PageResult;
import cn.com.pc.content.dto.PostDTO;
import cn.com.pc.content.dto.PostForm;
import cn.com.pc.content.dto.Sort;
import cn.com.pc.content.service.ContentService;
import cn.com.pc.content.util.BeanUtils;
import cn.com.pc.content.util.IpUtils;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashSet;

/**
 * 帖子 controller
 */
@RestController
@RequestMapping("/posts")
@Slf4j
public class PostController {

    @Autowired
    private ContentService contentService;

    @Autowired
    private HttpServletRequest request;

    /**
     * 查询帖子列表
     * @param site 站点
     * @param biz 业务
     * @param postForm 帖子查询表单
     * @param sort 排序
     * @return
     */
    @GetMapping
    public PageResult<?> listPostByForm(@RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, PostForm postForm, Sort sort) {
        postForm.setSite(site);
        postForm.setBiz(biz);
        return contentService.listContentByForm(postForm, sort, ContentType.Post);
    }


    /**
     * 查询帖子详情
     * @param site
     * @param biz
     * @param postId
     * @return
     */
    @GetMapping("/{postId:\\w+}")
    public PostDTO getPost(@RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, @PathVariable("postId") String postId) {
        PostDTO post = (PostDTO) contentService.getContent(postId, site, biz, ContentType.Post);
        if (post == null) {
            throw new PostNotFoundException();
        }
        return post;
    }


    /**
     * 新增帖子
     * @param site 站点
     * @param biz 业务
     * @param postDTO 帖子实体
     * @return
     * @throws IOException
     */
    @PostMapping
    @LogRequired(operation = "'新增帖子' + #_return")
    public String createPost(@RequestAttribute(Constants.AAA_IDENTITY) Identity identity, @RequestAttribute("site") Site site, @RequestAttribute("biz") Biz biz, @Validated @RequestBody PostDTO postDTO){
        // 查重
        Post post = (Post) contentService.getContentByReferId(postDTO.getReferId(), site, biz, ContentType.Post);
        if (post != null) {
            postDTO.setUpdatedBy(identity.getName());
            postDTO.setUpdatedAt(LocalDateTime.now());
            postDTO.setIp(IpUtils.getIp(request));
            post = (Post) contentService.updateContent(postDTO, post, ContentType.Post);
            return post.getId();
        }

        postDTO.setSite(site);
        postDTO.setBiz(biz);
        postDTO.setCreatedAt(LocalDateTime.now());
        postDTO.setCreatedBy(identity.getName());
        postDTO.setUpdatedAt(LocalDateTime.now());
        postDTO.setUpdatedBy(identity.getName());
        postDTO.setIp(IpUtils.getIp(request));

        post = new Post();
        post = (Post) contentService.createContent(postDTO, post, ContentType.Post);
        return post.getId();
    }


    /**
     * 修改帖子
     * @param site
     * @param biz
     * @param postId
     * @param postDTO
     * @return
     */
    @PutMapping("/{postId:\\w+}")
    @LogRequired(operation = "'修改帖子' + #postId")
    public Post updatePost(@RequestAttribute(Constants.AAA_IDENTITY) Identity identity, @RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, @PathVariable("postId") String postId, @Validated @RequestBody PostDTO postDTO) {
        // 判空
        Post post = (Post) contentService.getContentById(postId, ContentType.Post);
        if(post == null || post.getSite() != site) {
            throw new PostNotFoundException();
        }

        postDTO.setUpdatedBy(identity.getName());
        postDTO.setUpdatedAt(LocalDateTime.now());
        postDTO.setIp(IpUtils.getIp(request));
        try {
            request.setAttribute("operation", "，修改属性" + BeanUtils.comparePropertyIgnore(post, postDTO, "id", "ip", "auditStatus", "risk", "statData", "createdAt", "createdBy", "updatedAt", "updatedBy", "onShelve"));
        } catch (Exception e) {
            log.warn("帖子{}生成修改日志有误", postId);
            e.printStackTrace();
        }
        return (Post) contentService.updateContent(postDTO, post, ContentType.Post);
    }


    /**
     * 部分修改帖子
     * @param site
     * @param biz
     * @param postDTO
     * @return
     */
    @PatchMapping
    @LogRequired(operation = "'部分修改帖子' + #_return.getId()")
    public Post partialUpdatePost(@RequestAttribute(Constants.AAA_IDENTITY) Identity identity, @RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, @RequestBody PostDTO postDTO) {
        // 判空
        String referId = postDTO.getReferId();
        String id = postDTO.getId();
        Post post = null;
        if (StringUtils.hasLength(referId) && biz != null) {
            post = (Post) contentService.getContentByReferId(referId, site, biz, ContentType.Post);
        } else if (StringUtils.hasLength(id)){
            post = (Post) contentService.getContentById(id, ContentType.Post);
        }

        if(post == null) {
            throw new PostNotFoundException();
        }

        postDTO.setUpdatedBy(identity.getName());
        postDTO.setUpdatedAt(LocalDateTime.now());
        postDTO.setIp(IpUtils.getIp(request));
        return (Post) contentService.partialUpdateContent(postDTO, post, ContentType.Post);
    }


    /**
     * 上下架帖子
     * @param site
     * @param biz
     * @param postId
     */
    @PatchMapping("/{postId:\\w+}")
    @LogRequired(operation = "(#json.get('onShelve').asBoolean() == true ? '上架' : '下架') + '帖子' + #postId")
    public Post shelvePost(@RequestAttribute(Constants.AAA_IDENTITY) Identity identity, @RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, @PathVariable("postId") String postId, @RequestBody JsonNode json) {
        if (json.get("onShelve") == null) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "onShelve不能为空");
        }
        boolean onShelve = json.get("onShelve").asBoolean();

        // 判空
        Post post = (Post) contentService.getContentById(postId, ContentType.Post);
        if(post == null || post.getSite() != site) {
            throw new PostNotFoundException();
        }

        if (post.isOnShelve() == onShelve) {
            return post;
        }


        if (onShelve && post.getAuditStatus() != AuditStatus.Publish) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "帖子未发布");
        }

        post.setUpdatedBy(identity.getName());
        post.setUpdatedAt(LocalDateTime.now());
        post.setOnShelve(onShelve);
        return (Post) contentService.shelveContent(post, ContentType.Post);
    }


    /**
     * 删除帖子
     * @param site
     * @param biz
     * @param postId
     */
    @DeleteMapping("/{postId:\\w+}")
    @LogRequired(operation = "'删除帖子' + #postId")
    public void deletePost(@RequestAttribute(Constants.AAA_IDENTITY) Identity identity, @RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, @PathVariable("postId") String postId) {
        // 判空
        Post post = (Post) contentService.getContentById(postId, ContentType.Post);
        if(post == null || post.getSite() != site) {
            throw new PostNotFoundException();
        }

        post.setUpdatedBy(identity.getName());
        post.setUpdatedAt(LocalDateTime.now());
        contentService.deleteContent(post, ContentType.Post);
    }


    /**
     * 帖子打标签
     * @param site
     * @param biz
     * @param postId
     * @param postDTO
     * @return
     */
    @PutMapping("/{postId:\\w+}/tags")
    @LogRequired(operation = "'帖子打标签' + #postId")
    public Post updatePostTag(@RequestAttribute(Constants.AAA_IDENTITY) Identity identity, @RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, @PathVariable("postId") String postId, @RequestBody PostDTO postDTO) {
        if (CollectionUtils.isEmpty(postDTO.getTagIds())) {
            postDTO.setTagIds(new HashSet<>() {});
        }
        // 判空
        Post post = (Post) contentService.getContentById(postId, ContentType.Post);
        if(post == null || post.getSite() != site) {
            throw new PostNotFoundException();
        }

        post.setUpdatedBy(identity.getName());
        post.setUpdatedAt(LocalDateTime.now());
        try {
            request.setAttribute("operation", "，修改属性" + BeanUtils.comparePropertyWith(post, postDTO, "tagIds"));
        } catch (Exception e) {
            log.warn("帖子{}生成修改日志有误", postId);
            e.printStackTrace();
        }
        return (Post) contentService.updateContentTag(post, postDTO, ContentType.Post);
    }

}
